﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Net;
using System.Runtime.CompilerServices;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using DotNet.Utilities.ConsoleHelper;
using Newtonsoft.Json;

namespace BlogApiTestApp
{
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window, INotifyPropertyChanged
    {
        #region Bindable

        public event PropertyChangedEventHandler PropertyChanged;

        protected void OnPropertyChanged([CallerMemberName] string propertyName = null)
        {
            var eventHandler = this.PropertyChanged;
            eventHandler?.Invoke(this, new PropertyChangedEventArgs(propertyName));
        }

        protected bool SetProperty<T>(ref T storage, T value, [CallerMemberName] String propertyName = null)
        {
            if (Equals(storage, value)) return false;

            storage = value;
            this.OnPropertyChanged(propertyName);
            return true;
        }

        private string _Url = "https://localhost:44354/Api/";
        public string Url
        {
            get => _Url;
            set => SetProperty(ref _Url, value);
        }

        private string _UserName = "wlh";
        public string UserName
        {
            get => _UserName;
            set => SetProperty(ref _UserName, value);
        }

        private string _Password = "123456";
        public string Password
        {
            get => _Password;
            set => SetProperty(ref _Password, value);
        }

        private string _BlogTitle = "BlogApiTestApp";
        public string BlogTitle
        {
            get => _BlogTitle;
            set => SetProperty(ref _BlogTitle, value);
        }

        private string _BlogContent = "**本内容由BlogApiTestApp程序自动生成**";
        public string BlogContent
        {
            get => _BlogContent;
            set => SetProperty(ref _BlogContent, value);
        }

        private string _Info = "**此处显示操作信息**\r\n";
        public string Info
        {
            get => _Info;
            set => SetProperty(ref _Info, value);
        }

        #endregion

        #region Command

        public ICommand GetTokenCommand { get; set; }

        public ICommand GetBlogListCommand { get; set; }

        public ICommand AddBlogCommand { get; set; }

        #endregion

        public string Token { get; set; }

        public MainWindow()
        {
            InitializeComponent();
            this.DataContext = this;
            Console.SetOut(new ConsoleWriter(s => { Info += $"{s}\r\n"; }));
            SetCommandMethod();
        }

        /// <summary>
        /// 命令方法赋值(在构造函数中调用)
        /// </summary>
        private void SetCommandMethod()
        {
            GetTokenCommand ??= new RelayCommand(o => !(string.IsNullOrEmpty(UserName) || string.IsNullOrEmpty(Password)), async o =>
            {
                var req = new ReqGetToken()
                {
                    userName = UserName,
                    password = Password,
                };

                var res = await GetToken(req);
                if (res.Code)
                {
                    Token = res.Token;
                }
            });

            GetBlogListCommand ??= new RelayCommand(o => !string.IsNullOrEmpty(Token), async o =>
            {
                await GetList(new ReqGetList());
            });

            AddBlogCommand ??= new RelayCommand(o => !string.IsNullOrEmpty(Token), async o =>
            {
                var req = new ReqAddBlog()
                {
                    UserName = UserName,
                    Title = BlogTitle,
                    Content = BlogContent,
                    DTCreate = DateTime.Now,
                };

                await AddBlog(req);
            });
        }

        #region API

        private async Task<ResGetToken> GetToken(ReqGetToken req)
        {
            req.MethodName = "GetToken";
            req.MethodDesc = "获取Token";
            req.MethodType = "GET";

            return await JsonGetTaskAsync<ReqGetToken, ResGetToken>(req);
        }

        private async Task<ResGetList> GetList(ReqGetList req)
        {
            req.MethodName = "GetList";
            req.MethodDesc = "获取博文列表";
            req.MethodType = "GET";

            return await JsonGetTaskAsync<ReqGetList, ResGetList>(req);
        }

        private async Task<ResAddBlog> AddBlog(ReqAddBlog req)
        {
            req.MethodName = "Add";
            req.MethodDesc = "添加文章";
            req.MethodType = "POST";

            return await JsonPostTaskAsync<ReqAddBlog, ResAddBlog>(req);
        }

        #endregion

        #region Method

        private async Task<T2> JsonPostTaskAsync<T1, T2>(T1 req)
        where T1 : ReqBase, new()
        where T2 : ResBase, new()
        {
            try
            {
                System.Net.ServicePointManager.ServerCertificateValidationCallback = (sender, cert, chain, errors) => true;
                string functionName = $"{req.MethodName}-{req.MethodDesc}-{req.MethodType}";
                Console.WriteLine("\r\n-------------" + functionName);

                string url = $"{_Url}{req.MethodName}";
                string reqStr = JsonConvert.SerializeObject(req, new JsonSerializerSettings() { DateFormatString = "yyyy-MM-dd HH:mm:ss", });
                Console.WriteLine($"【发送】{url}\r\n{reqStr}");

                using (WebClient wc = new WebClient { Encoding = Encoding.UTF8 })
                {
                    wc.Headers.Add("Content-Type", "application/json");
                    //wc.Headers.Add("token", Token);

                    var ret = await wc.UploadDataTaskAsync($"{url}?token={Token}", Encoding.UTF8.GetBytes(reqStr));
                    var retStr = Encoding.UTF8.GetString(ret);

                    #region 接收日志

                    string logStr = retStr;
                    //string logStr = ConvertJson.JsonStringFormat(retStr, false);
                    //int len = logStr.Length;
                    //if (len > LogMaxLength)
                    //{
                    //    logStr = $"{logStr.Substring(0, LogMaxLength / 2)}【...】{logStr.Substring(len - LogMaxLength / 2)}";
                    //}
                    Console.WriteLine($"【接收】{logStr}");

                    #endregion

                    var retval = JsonConvert.DeserializeObject<T2>(retStr);
                    return retval;
                }
            }
            catch (Exception ex)
            {
                Console.WriteLine($"网络通信出错：{ex}");
                return new T2 { Code = false, Message = $"网络通信出错：{ex.Message}" };
            }
        }

        private async Task<T2> JsonGetTaskAsync<T1, T2>(T1 req)
        where T1 : ReqBase, new()
        where T2 : ResBase, new()
        {
            try
            {
                System.Net.ServicePointManager.ServerCertificateValidationCallback = (sender, cert, chain, errors) => true;
                string functionName = $"{req.MethodName}-{req.MethodDesc}-{req.MethodType}";
                Console.WriteLine("\r\n-------------" + functionName);

                string url = $"{_Url}{req.MethodName}"; //API地址
                List<string> reqPairs = new List<string>();
                foreach (var p in req.GetType().GetProperties())
                {
                    var attributes = p.GetCustomAttributes(typeof(JsonIgnoreAttribute), true);
                    if (attributes.Length > 0)
                    {
                        continue;
                    }

                    object value = p.GetValue(req);
                    if (value is DateTime)
                    {
                        if ((DateTime)value == DateTime.MinValue)
                        {
                            continue;
                        }

                        value = ((DateTime)value).ToString("yyyy-MM-dd HH:mm:ss");
                    }
                    else if (value == null)
                    {
                        continue;
                    }

                    reqPairs.Add(p.Name + "=" + value);
                }
                string reqStr = $"{url}?token={Token}&{string.Join("&", reqPairs)}";
                Console.WriteLine($"【发送】{reqStr}");

                using (WebClient wc = new WebClient { Encoding = Encoding.UTF8 })
                {
                    wc.Headers.Add("Content-Type", "application/json");
                    //wc.Headers.Add("token", _Token);

                    var ret = await wc.DownloadDataTaskAsync(reqStr);  // GET 方式
                    var retStr = Encoding.UTF8.GetString(ret);

                    #region 接收日志

                    string logStr = retStr;
                    //string logStr = ConvertJson.JsonStringFormat(retStr, false);
                    //int len = logStr.Length;
                    //if (len > LogMaxLength)
                    //{
                    //    logStr = $"{logStr.Substring(0, LogMaxLength / 2)}【...】{logStr.Substring(len - LogMaxLength / 2)}";
                    //}
                    Console.WriteLine($"【接收】{logStr}");

                    #endregion

                    var retval = JsonConvert.DeserializeObject<T2>(retStr);
                    return retval;
                }
            }
            catch (Exception ex)
            {
                Console.WriteLine($"网络通信出错：{ex}");
                return new T2 { Code = false, Message = $"网络通信出错：{ex.Message}" };
            }
        }

        #endregion
    }
}
